home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume36 / log_tcp / part03 < prev    next >
Encoding:
Text File  |  1993-03-07  |  39.4 KB  |  1,200 lines

  1. Newsgroups: comp.sources.misc
  2. From: wietse@wzv.win.tue.nl (Wietse Venema)
  3. Subject: v36i006:  log_tcp - TCP/IP daemon wrapper, v5.0, Part03/03
  4. Message-ID: <1993Mar8.041425.22570@sparky.imd.sterling.com>
  5. X-Md4-Signature: ad4b614210ac9ec1cbeebd6f5640e9e5
  6. Date: Mon, 8 Mar 1993 04:14:25 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: wietse@wzv.win.tue.nl (Wietse Venema)
  10. Posting-number: Volume 36, Issue 6
  11. Archive-name: log_tcp/part03
  12. Environment: UNIX
  13. Supersedes: log_tcp: Volume 30, Issue 79-80
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 3 (of 3)."
  22. # Contents:  Makefile.dist hosts_access.c options.c
  23. # Wrapped by wietse@wzv on Sun Mar  7 22:58:27 1993
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f Makefile.dist -a "${1}" != "-c" ; then 
  26.   echo shar: Will not over-write existing file \"Makefile.dist\"
  27. else
  28. echo shar: Extracting \"Makefile.dist\" \(15298 characters\)
  29. sed "s/^X//" >Makefile.dist <<'END_OF_Makefile.dist'
  30. X# @(#) Makefile.dist 1.1 93/03/07 22:47:45
  31. X# 
  32. X# If you did not already do so, copy the file Makefile.dist to Makefile
  33. X# and edit the copy, not the original. Have a copy of the README file at
  34. X# hand while editing. It gives some additional background.
  35. X#
  36. X# For your convenience, all configurable parameters have been moved into
  37. X# the Makefile, so that you do not have to hack the source files anymore.
  38. X#
  39. X# Some parameters must always be set to match the operating environment.
  40. X# Other parameter settings are a matter of taste. Their sections headings
  41. X# are labeled "(Optional)". The defaults correspond to the programs as
  42. X# documented in the manual pages.
  43. X
  44. X######################################################
  45. X# Choice between easy and advanced installation recipe
  46. X# 
  47. X# According to the easy installation recipe in the README file, vendor-
  48. X# provided network daemons are moved to "some other" directory, and the
  49. X# tcpd wrapper fills in the "holes". For this mode of operation, the
  50. X# REAL_DAEMON_DIR macro should be set to the "some other" directory.
  51. X# Uncomment the appropriate line. The "..." is here for historical
  52. X# reasons only; you will probably want to use some other name. Watch out
  53. X# for the quotes and backslashes.
  54. X
  55. XREAL_DAEMON_DIR=\"/usr/etc/...\"    # BSD 4.3 Ultrix 4.x SunOS 4.x
  56. X#REAL_DAEMON_DIR=\"/usr/sbin/...\"    # SysV.4 Solaris 2.x
  57. X#REAL_DAEMON_DIR=\"/usr/libexec/...\"    # BSD 4.4
  58. X
  59. X# According to the advanced installation recipe, vendor-provided daemons
  60. X# are left alone, and the inetd file is edited instead. In that case, the
  61. X# REAL_DAEMON_DIR macro should reflect the actual directory with (most of)
  62. X# your vendor-provided network daemons.  Uncomment the appropriate line.
  63. X
  64. X#REAL_DAEMON_DIR=\"/usr/etc\"        # BSD 4.3 Ultrix 4.x SunOS 4.x
  65. X#REAL_DAEMON_DIR=\"/usr/sbin\"        # SysV.4 Solaris 2.x
  66. X#REAL_DAEMON_DIR=\"/usr/libexec\"    # BSD 4.4
  67. X
  68. X#########################################################
  69. X# Differences between ranlib(1) and ar(1) implementations
  70. X#
  71. X# Some C compilers (Ultrix 4.x) insist that ranlib(1) be run on an object
  72. X# library; some don't care as long as the modules are in the right order;
  73. X# some systems don't even have a ranlib(1) command. SGI IRIX uses the 's'
  74. X# option to the 'ar' command instead. Make your choice.
  75. X
  76. XRANLIB    = ranlib    # have ranlib (BSD-ish UNIX)
  77. X#RANLIB    = echo        # no ranlib (SYSV-ish UNIX)
  78. X
  79. XARFLAGS    = rv        # OK for most systems
  80. X#ARFLAGS= rvs        # ranlib flag for 'ar' on IRIX 4.0.x
  81. X
  82. X#######################################################
  83. X# Routines that are not present in the system libraries
  84. X# 
  85. X# The strcasecmp.c file provided with this package comes from 4.3+BSD
  86. X# UNIX. The setenv.c module is a re-implementation of the 4.4 BSD one.
  87. X# strtok.c comes from 4.4BSD. 
  88. X
  89. XAUX_OBJ    = setenv.o            # no setenv(3)
  90. X#AUX_OBJ= setenv.o strcasecmp.o        # no setenv(3) and no strcasecmp(3)
  91. X#AUX_OBJ= setenv.o strcasecmp.o strtok.o
  92. X
  93. X# While building the file strcasecmp.o, the compiler may complain that
  94. X# u_char is undefined. Uncomment the following definition for a fix.
  95. X#
  96. X#UCHAR    = -Du_char="unsigned char"    # no u_char type
  97. X
  98. X# Uncomment the following if your C library has index/rindex/bcmp
  99. X# but does not provide the strchr/strrchr/memcmp routines. If that
  100. X# is the case, you probably also do not have strtok() (see above).
  101. X#
  102. X#STRINGS= -Dindex=strchr -Drindex=strrchr -Dmemcmp=bcmp
  103. X
  104. X###########################################
  105. X# Selection of non-default object libraries
  106. X#
  107. X# Many System-V versions require that you explicitly specify the networking
  108. X# libraries (for example, -lnet or -linet).
  109. X#
  110. X#LIBS    = -lsocket -lnsl    # SysV.4 Solaris 2.x
  111. X#LIBS    = -lsun            # IRIX
  112. X
  113. X#########################
  114. X# Ultrix-specific section
  115. X#
  116. X# Ultrix users may want to use the miscd wrapper, too. The Ultrix miscd
  117. X# implements among others the SYSTAT service which runs the WHO command,
  118. X# and thus provides a subset of the finger service. The very first wrapper
  119. X# application (in the early hours of May 20, 1990) was to monitor SYSTAT.
  120. X
  121. Xall:    tcpd try            # no Ultrix miscd
  122. X#all:    tcpd try miscd            # Ultrix, monitor systat etc. too
  123. X
  124. X#REAL_MISCD=\"/usr/etc/.../miscd\"    # easy installation
  125. X#REAL_MISCD=\"/usr/etc/miscd\"        # advanced installation
  126. X
  127. X################################
  128. X# System-specific compiler flags
  129. X#
  130. X# Apollo Domain/OS offers both bsd and sys5 environments, sometimes
  131. X# on the same machine.  If your Apollo is primarily sys5.3 and also
  132. X# has bsd4.3, uncomment the following to build under bsd and run under
  133. X# either environment.
  134. X#
  135. X#SYSTYPE= -A run,any -A sys,any
  136. X
  137. X# For MIPS RISC/os 4_52.p3, uncomment the following definition.
  138. X#
  139. X#SYSTYPE= -sysname bsd43
  140. X
  141. X############################
  142. X# Working around system bugs
  143. X#
  144. X# Some versions of Apollo or SYSV.4 UNIX have a bug in the getpeername(2)
  145. X# routine.  You may have this bug when the wrapper reports that all UDP
  146. X# connections come from address 0.0.0.0. Compile with -DGETPEERNAME_BUG
  147. X# for a workaround. The workaround does no harm on other systems. If in
  148. X# doubt, leave it in.
  149. X#
  150. X# Some System V versions (Solaris 2) have a problem in the recvfrom()
  151. X# emulation code.  You may have this bug when the wrapper programs
  152. X# complain about "unexpected address family 0" when processing an UDP
  153. X# request. Compile with -DRECVFROM_BUG for a workaround. The workaround
  154. X# does no harm on other systems. If in doubt, leave it in.
  155. X# 
  156. X# With some System V implementations (SCO UNIX 3.2v4), even compiling
  157. X# with -DRECVFROM_BUG does not solve the "address family 0" problem. If
  158. X# that is the case, compile with -DADDRESS_FAMILY_BUG instead.
  159. X#
  160. X# DG/UX 5.4.1 comes with an inet_ntoa() function that returns a structure
  161. X# instead of a long integer. Compile with -DINET_ADDR_BUG to work around
  162. X# this mutant behavour.
  163. X
  164. XBUGS    = -DGETPEERNAME_BUG -DRECVFROM_BUG # -DADDRESS_FAMILY_BUG
  165. X
  166. X####################################################
  167. X# Whether or not your system has NIS (or YP) support
  168. X#
  169. X# If your system supports NIS or YP-style netgroups, enable the following
  170. X# macro definition. Netgroups are used only for host access control.
  171. X#
  172. X#NETGROUP= -DNETGROUP
  173. X
  174. X# End of the required configuration options; all other ones are optional.
  175. X#########################################################################
  176. X
  177. X################################################################
  178. X# Changing the default disposition of logfile records (Optional)
  179. X#
  180. X# By default, logfile entries are written to the same file as used for
  181. X# sendmail transaction logs. See your /etc/syslog.conf file for actual
  182. X# path names of logfiles. The tutorial section in the README file
  183. X# gives a brief introduction to the syslog daemon.
  184. X# 
  185. X# Change the FACILITY definition below if you disagree with the default
  186. X# disposition. Some syslog versions (including Ultrix 4.x) do not provide
  187. X# this flexibility.
  188. X# 
  189. X# If nothing shows up on your system, it may be that the syslog records
  190. X# are sent to a dedicated loghost. It may also be that no syslog daemon
  191. X# is running at all. The README file gives pointers to surrogate syslog
  192. X# implementations for systems that have no syslog library routines or
  193. X# no syslog daemons.
  194. X#
  195. X# The LOG_XXX names below are taken from the /usr/include/syslog.h file.
  196. X
  197. XFACILITY= LOG_MAIL    # LOG_MAIL is what most sendmail daemons use
  198. X
  199. X# The syslog priority at which successful connections are logged.
  200. X
  201. XSEVERITY= LOG_INFO    # LOG_INFO is normally not logged to the console
  202. X
  203. X#############################################
  204. X# Enabling remote username lookups (Optional)
  205. X#
  206. X# By default, the wrappers just report the remote host name (the host
  207. X# address if the host name lookup fails or times out).  Username lookups
  208. X# require that the remote host runs a daemon that supports a RFC 931 like
  209. X# protocol.  Remote user name lookups are not possible for UDP-based
  210. X# connections, and can cause noticeable delays with connections from
  211. X# non-UNIX PCs.  On some systems, remote username lookups can trigger a
  212. X# kernel bug, causing loss of service. The README file gives details on
  213. X# how to find out if your system has that problem.
  214. X# 
  215. X# Uncomment the following definition if the wrappers should always
  216. X# attempt to get the remote user name.
  217. X#
  218. X# The default username lookup timeout is 30 seconds.
  219. X#
  220. X#AUTH    = -DRFC931_TIMEOUT=30 -DRFC931
  221. X
  222. X# The USER_AT_HOST feature does selective username lookups. It triggers
  223. X# on access control patterns of the form xxx@yyy. Until now, such
  224. X# patterns were not used, so that USER_AT_HOST does not break existing
  225. X# rules.
  226. X# 
  227. X# The feature is not documented and is not yet intended for general use,
  228. X# because it can complicate the design of access control tables.
  229. X# 
  230. X# With USER_AT_HOST enabled, remote username lookups are done only for
  231. X# user_pattern@host_pattern expressions in the access control files, but
  232. X# only when the host_pattern matches. Example: "ALL: @pcgroup ALL@ALL"
  233. X# avoids user name lookups for members of the pcgroup netgroup.  The
  234. X# user_pattern syntax is identical to that of host_pattern, but "ALL"
  235. X# is usually the only user_pattern that makes sense.
  236. X# 
  237. X# The default username lookup timeout is 30 seconds.
  238. X#
  239. X#AUTH    = -DRFC931_TIMEOUT=30 -DUSER_AT_HOST
  240. X
  241. X########################################################
  242. X# Turning on experimental language extensions (Optional)
  243. X#
  244. X# Instead of the officially documented access control language, the
  245. X# software can be configured to implement a more experimental language
  246. X# that is easily extended. The experimental language is implemented by
  247. X# the "options.c" source module which also serves as its documentation.
  248. X
  249. XSTYLE    = -DOPTIONS_STYLE=shell_cmd        # The documented language
  250. X#STYLE    = -DOPTIONS_STYLE=process_options    # The experimental one
  251. X
  252. X######################################################
  253. X# Changing the default file protection mask (Optional)
  254. X#
  255. X# On many systems, network daemons and other system processes are started
  256. X# with a zero umask value, so that world-writable files may be produced.
  257. X# It is a good idea to edit your /etc/rc* files so that they begin with
  258. X# an explicit umask setting.  On our site we use `umask 022' because it
  259. X# does not break anything yet gives adequate protection against tampering.
  260. X# 
  261. X# The following macro specifies the default umask for processes run under
  262. X# control of the daemon wrappers. Comment it out only if you are certain
  263. X# that inetd and its children are started with a safe umask value.
  264. X
  265. XUMASK    = -DDAEMON_UMASK=022
  266. X
  267. X#######################################
  268. X# Turning off access control (Optional)
  269. X#
  270. X# By default, host access control is enabled.  To disable host access
  271. X# control, comment out the following definition.  Host access control
  272. X# can also be turned off at runtime by providing no or empty access
  273. X# control tables.
  274. X
  275. XACCESS    = -DHOSTS_ACCESS
  276. X
  277. X########################################################
  278. X# Changing the access control table pathnames (Optional)
  279. X#
  280. X# The HOSTS_ALLOW and HOSTS_DENY macros define where the programs will
  281. X# look for access control information. Watch out for the quotes and
  282. X# backslashes when you make changes.
  283. X
  284. XTABLES    = -DHOSTS_DENY=\"/etc/hosts.deny\" -DHOSTS_ALLOW=\"/etc/hosts.allow\"
  285. X
  286. X###########################################
  287. X# Turning off host NAME checking (Optional)
  288. X#
  289. X# By default, the software tries to protect against hosts that claim to
  290. X# have someone elses host name. This is relevant for network services
  291. X# whose authentication depends on host names, such as rsh and rlogin.
  292. X#
  293. X# With paranoid mode on, connections will be rejected when the host name
  294. X# does not match the host address. Connections will also be rejected when
  295. X# the host name cannot be verified because gethostbyname() fails.
  296. X#
  297. X# Comment out the following definition if you do not need this additional
  298. X# protection. If paranoid mode is off, and a host name check fails, the
  299. X# daemon wrappers will use only the host address, but your daemons may
  300. X# still use the host name.
  301. X
  302. XPARANOID= -DPARANOID
  303. X
  304. X##############################################
  305. X# Turning off host ADDRESS checking (Optional)
  306. X#
  307. X# By default, the software tries to protect against hosts that pretend to
  308. X# have someone elses host address. This is relevant for network services
  309. X# whose authentication depends on host names, such as rsh and rlogin,
  310. X# because the network address is used to look up the remote host name.
  311. X# 
  312. X# The protection is effective only when the offending host claims to have
  313. X# a network address that lies outside its own network.
  314. X#
  315. X# My site has been running rlogind and rshd daemons that implement this
  316. X# feature for more than 2 years, and without any ill effects.
  317. X#
  318. X# Comment out the following definition if you do not need the additional
  319. X# protection.
  320. X
  321. XKILL_OPT= -DKILL_IP_OPTIONS
  322. X
  323. X## End configuration options
  324. X############################
  325. X
  326. XCFLAGS    = -O -DFACILITY=$(FACILITY) $(ACCESS) $(PARANOID) $(NETGROUP) \
  327. X    $(BUGS) $(SYSTYPE) $(AUTH) $(UMASK) -DREAL_MISCD=$(REAL_MISCD) \
  328. X    -DREAL_DAEMON_DIR=$(REAL_DAEMON_DIR) $(STYLE) $(KILL_OPT) \
  329. X    -DSEVERITY=$(SEVERITY) $(UCHAR) $(TABLES) $(STRINGS)
  330. X
  331. XLIB_OBJ= hosts_access.o options.o shell_cmd.o rfc931.o hosts_info.o \
  332. X    hosts_ctl.o refuse.o percent_x.o clean_exit.o $(AUX_OBJ) \
  333. X    fromhost.o fix_options.o
  334. X
  335. XKIT    = README miscd.c tcpd.c fromhost.c hosts_access.c shell_cmd.c \
  336. X    log_tcp.h try.c refuse.c Makefile.dist hosts_access.5 strcasecmp.c \
  337. X    BLURB rfc931.c tcpd.8 hosts_info.c hosts_access.3 hosts_ctl.c \
  338. X    percent_x.c options.c clean_exit.c setenv.c patchlevel.h strtok.c \
  339. X    fix_options.c inet_addr_fix
  340. X
  341. XLIB    = libwrap.a
  342. X
  343. X$(LIB):    $(LIB_OBJ)
  344. X    rm -f $(LIB)
  345. X    ar $(ARFLAGS) $(LIB) $(LIB_OBJ)
  346. X    $(RANLIB) $(LIB)
  347. X
  348. Xtcpd:    tcpd.o fromhost.o $(LIB)
  349. X    $(CC) $(CFLAGS) -o $@ tcpd.o fromhost.o $(LIB) $(LIBS)
  350. X
  351. Xmiscd:    miscd.o fromhost.o $(LIB)
  352. X    $(CC) $(CFLAGS) -o $@ miscd.o fromhost.o $(LIB) $(LIBS)
  353. X
  354. Xtry:    try.o $(LIB)
  355. X    $(CC) $(CFLAGS) -o $@ try.o $(LIB) $(LIBS)
  356. X
  357. Xfromhost: fromhost.c log_tcp.h Makefile $(LIB)
  358. X    $(CC) $(CFLAGS) -DTEST -o fromhost fromhost.c $(LIB) $(LIBS)
  359. X    rm -f fromhost.o
  360. X
  361. Xshar:    $(KIT)
  362. X    @shar $(KIT)
  363. X
  364. Xkit:    $(KIT)
  365. X    @makekit $(KIT)
  366. X
  367. Xarchive:
  368. X    $(ARCHIVE) $(KIT)
  369. X
  370. Xclean:
  371. X    rm -f tcpd miscd try fromhost *.[oa] core
  372. X
  373. X# Enable all bells and whistles for linting.
  374. X
  375. Xlint: tcpd_lint miscd_lint try_lint
  376. X
  377. Xtcpd_lint:
  378. X    lint -DFACILITY=LOG_MAIL -DHOSTS_ACCESS -DPARANOID -DNETGROUP \
  379. X    -DGETPEERNAME_BUG -DDAEMON_UMASK=022 -DSEVERITY=$(SEVERITY) \
  380. X    -DUSER_AT_HOST -DKILL_IP_OPTIONS -DOPTIONS_STYLE=process_options \
  381. X    tcpd.c fromhost.c hosts_access.c shell_cmd.c refuse.c rfc931.c \
  382. X    hosts_info.c percent_x.c clean_exit.c options.c setenv.c fix_options.c
  383. X
  384. Xmiscd_lint:
  385. X    lint -DFACILITY=LOG_MAIL -DHOSTS_ACCESS -DPARANOID -DNETGROUP \
  386. X    -DGETPEERNAME_BUG -DDAEMON_UMASK=022 -DSEVERITY=$(SEVERITY) \
  387. X    -DUSER_AT_HOST -DKILL_IP_OPTIONS -DOPTIONS_STYLE=process_options \
  388. X    miscd.c fromhost.c hosts_access.c shell_cmd.c refuse.c rfc931.c \
  389. X    hosts_info.c percent_x.c clean_exit.c options.c setenv.c fix_options.c
  390. X
  391. Xtry_lint:
  392. X    lint -DFACILITY=LOG_MAIL -DHOSTS_ACCESS -DNETGROUP try.c \
  393. X    hosts_ctl.c hosts_access.c hosts_info.c percent_x.c
  394. X
  395. X# Compilation dependencies.
  396. X
  397. Xclean_exit.o: log_tcp.h Makefile
  398. Xfix_options.o: log_tcp.h Makefile
  399. Xfromhost.o: log_tcp.h Makefile
  400. Xhosts_access.o: log_tcp.h Makefile
  401. Xhosts_ctl.o: log_tcp.h Makefile
  402. Xhosts_info.o: log_tcp.h Makefile
  403. Xmiscd.o: patchlevel.h log_tcp.h Makefile
  404. Xoptions.o: log_tcp.h Makefile
  405. Xpercent_x.o: log_tcp.h Makefile
  406. Xrefuse.o: log_tcp.h Makefile
  407. Xrfc931.o: log_tcp.h Makefile
  408. Xshell_cmd.o: log_tcp.h Makefile
  409. Xtcpd.o: patchlevel.h log_tcp.h Makefile
  410. Xtry.o: log_tcp.h Makefile
  411. END_OF_Makefile.dist
  412. if test 15298 -ne `wc -c <Makefile.dist`; then
  413.     echo shar: \"Makefile.dist\" unpacked with wrong size!
  414. fi
  415. # end of overwriting check
  416. fi
  417. if test -f hosts_access.c -a "${1}" != "-c" ; then 
  418.   echo shar: Will not over-write existing file \"hosts_access.c\"
  419. else
  420. echo shar: Extracting \"hosts_access.c\" \(11173 characters\)
  421. sed "s/^X//" >hosts_access.c <<'END_OF_hosts_access.c'
  422. X /*
  423. X  * This module implements a simple access control language that is based on
  424. X  * host (or domain) names, netgroup, internet addresses (or network numbers)
  425. X  * and daemon process names. When a match is found an optional shell command
  426. X  * is executed and the search is terminated.
  427. X  * 
  428. X  * Diagnostics are reported through syslog(3).
  429. X  * 
  430. X  * Compile with -DNETGROUP if your library provides support for netgroups.
  431. X  * 
  432. X  * Compile with -DUSER_AT_HOST for rule-driven username lookups.
  433. X  * 
  434. X  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  435. X  */
  436. X
  437. X#ifndef lint
  438. Xstatic char sccsid[] = "@(#) hosts_access.c 1.10 93/03/07 22:47:36";
  439. X#endif
  440. X
  441. X /* System libraries. */
  442. X
  443. X#include <sys/types.h>
  444. X#include <sys/param.h>
  445. X#include <netinet/in.h>
  446. X#include <arpa/inet.h>
  447. X#include <stdio.h>
  448. X#include <syslog.h>
  449. X#include <ctype.h>
  450. X#include <errno.h>
  451. X
  452. Xextern char *fgets();
  453. Xextern char *strchr();
  454. Xextern char *strtok();
  455. X
  456. X#ifndef    INADDR_NONE
  457. X#define    INADDR_NONE    (-1)        /* XXX should be 0xffffffff */
  458. X#endif
  459. X
  460. X/* Local stuff. */
  461. X
  462. X#include "log_tcp.h"
  463. X
  464. X#ifdef INET_ADDR_BUG
  465. X#include "inet_addr_fix"
  466. X#endif
  467. X
  468. X/* Delimiters for lists of daemons or clients. */
  469. X
  470. Xstatic char sep[] = ", \t";
  471. X
  472. X/* Constants to be used in assignments only, not in comparisons... */
  473. X
  474. X#define    YES        1
  475. X#define    NO        0
  476. X#define    FAIL        (-1)
  477. X
  478. X/* Forward declarations. */
  479. X
  480. Xstatic int table_match();
  481. Xstatic int list_match();
  482. Xstatic int client_match();
  483. Xstatic int string_match();
  484. Xstatic int masked_match();
  485. Xstatic char *xgets();
  486. X
  487. X/* The user@host access control. Trivial to add but complicates use. */
  488. X
  489. X#ifdef USER_AT_HOST
  490. Xstatic int userhost_match();
  491. X#define CLIENT_MATCH userhost_match
  492. X#else
  493. X#define CLIENT_MATCH client_match
  494. X#endif
  495. X
  496. X/* Size of logical line buffer. */
  497. X
  498. X#define    BUFLEN 2048
  499. X
  500. X/* hosts_access - host access control facility */
  501. X
  502. Xint     hosts_access(daemon, client)
  503. Xchar   *daemon;
  504. Xstruct from_host *client;        /* host or user name may be empty */
  505. X{
  506. X
  507. X    /*
  508. X     * If the (daemon, client) pair is matched by an entry in the file
  509. X     * /etc/hosts.allow, access is granted. Otherwise, if the (daemon,
  510. X     * client) pair is matched by an entry in the file /etc/hosts.deny,
  511. X     * access is denied. Otherwise, access is granted. A non-existent
  512. X     * access-control file is treated as an empty file.
  513. X     */
  514. X
  515. X    if (table_match(HOSTS_ALLOW, daemon, client))
  516. X    return (YES);
  517. X    if (table_match(HOSTS_DENY, daemon, client))
  518. X    return (NO);
  519. X    return (YES);
  520. X}
  521. X
  522. X/* table_match - match table entries with (daemon, client) pair */
  523. X
  524. Xstatic int table_match(table, daemon, client)
  525. Xchar   *table;
  526. Xchar   *daemon;
  527. Xstruct from_host *client;        /* host or user name may be empty */
  528. X{
  529. X    FILE   *fp;
  530. X    char    sv_list[BUFLEN];        /* becomes list of daemons */
  531. X    char   *cl_list;            /* becomes list of clients */
  532. X    char   *sh_cmd;            /* becomes optional shell command */
  533. X    int     match;
  534. X    int     end;
  535. X
  536. X    /* The following variables should always be tested together. */
  537. X
  538. X    int     sv_match = NO;        /* daemon matched */
  539. X    int     cl_match = NO;        /* client matced */
  540. X
  541. X    /*
  542. X     * Process the table one logical line at a time. Lines that begin with a
  543. X     * '#' character are ignored. Non-comment lines are broken at the ':'
  544. X     * character (we complain if there is none). The first field is matched
  545. X     * against the daemon process name (argv[0]), the second field against
  546. X     * the host name or address. A non-existing table is treated as if it
  547. X     * were an empty table. The search terminates at the first matching rule.
  548. X     * When a match is found an optional shell command is executed.
  549. X     */
  550. X
  551. X    if (fp = fopen(table, "r")) {
  552. X    while (!(sv_match && cl_match) && xgets(sv_list, sizeof(sv_list), fp)) {
  553. X        if (sv_list[end = strlen(sv_list) - 1] != '\n') {
  554. X        syslog(LOG_ERR, "%s: missing newline or line too long", table);
  555. X        continue;
  556. X        }
  557. X        if (sv_list[0] == '#')        /* skip comments */
  558. X        continue;
  559. X        while (end > 0 && isspace(sv_list[end - 1]))
  560. X         end--;
  561. X        sv_list[end] = '\0';        /* strip trailing whitespace */
  562. X        if (sv_list[0] == 0)        /* skip blank lines */
  563. X        continue;
  564. X        if ((cl_list = strchr(sv_list, ':')) == 0) {
  565. X        syslog(LOG_ERR, "%s: malformed entry: \"%s\"", table, sv_list);
  566. X        continue;
  567. X        }
  568. X        *cl_list++ = '\0';            /* split 1st and 2nd fields */
  569. X        if ((sh_cmd = strchr(cl_list, ':')) != 0)
  570. X        *sh_cmd++ = '\0';        /* split 2nd and 3rd fields */
  571. X        if ((sv_match = list_match(sv_list, daemon, string_match)))
  572. X        cl_match = list_match(cl_list, (char *) client, CLIENT_MATCH);
  573. X    }
  574. X    (void) fclose(fp);
  575. X    } else if (errno != ENOENT) {
  576. X    syslog(LOG_ERR, "cannot open %s: %m", table);
  577. X    }
  578. X    match = (sv_match == YES && cl_match == YES);
  579. X    if (match && sh_cmd)
  580. X    OPTIONS_STYLE(sh_cmd, daemon, client);
  581. X    return (match);
  582. X}
  583. X
  584. X/* list_match - match an item against a list of tokens with exceptions */
  585. X
  586. Xstatic int list_match(list, item, match_fn)
  587. Xchar   *list;
  588. Xchar   *item;
  589. Xint   (*match_fn) ();
  590. X{
  591. X    char   *tok;
  592. X    int     match = NO;
  593. X
  594. X    /*
  595. X     * Process tokens one at a time. We have exhausted all possible matches
  596. X     * when we reach an "EXCEPT" token or the end of the list. If we do find
  597. X     * a match, look for an "EXCEPT" list and recurse to determine whether
  598. X     * the match is affected by any exceptions.
  599. X     */
  600. X
  601. X    for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) {
  602. X    if (strcasecmp(tok, "EXCEPT") == 0)    /* EXCEPT: give up */
  603. X        break;
  604. X    if (match = (*match_fn) (tok, item))    /* YES or FAIL */
  605. X        break;
  606. X    }
  607. X    /* Process exceptions to YES or FAIL matches. */
  608. X
  609. X    if (match != NO) {
  610. X    while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
  611. X         /* VOID */ ;
  612. X    if (tok == 0 || list_match((char *) 0, item, match_fn) == NO)
  613. X        return (match);
  614. X    }
  615. X    return (NO);
  616. X}
  617. X
  618. X/* client_match - match host name and address against token */
  619. X
  620. Xstatic int client_match(tok, item)
  621. Xchar   *tok;
  622. Xchar   *item;
  623. X{
  624. X    struct from_host *client = (struct from_host *) item;
  625. X    int     match;
  626. X
  627. X    /*
  628. X     * Try to match the address first. If that fails, try to match the host
  629. X     * name if available.
  630. X     */
  631. X
  632. X    if ((match = string_match(tok, client->addr)) == 0)
  633. X    if (client->name[0] != 0)
  634. X        match = string_match(tok, client->name);
  635. X    return (match);
  636. X}
  637. X
  638. X#ifdef USER_AT_HOST
  639. X
  640. X/* userhost_match - do user@host access control */
  641. X
  642. Xstatic int userhost_match(tok, item)
  643. Xchar   *tok;
  644. Xchar   *item;
  645. X{
  646. X    struct from_host *client = (struct from_host *) item;
  647. X    int     match = NO;
  648. X    char   *at;
  649. X    int     host_match;
  650. X    int     user_match;
  651. X
  652. X    /*
  653. X     * Warning: experimental code, enabled only when USER_AT_HOST is defined.
  654. X     * 
  655. X     * Basically, you specify user_pattern@host_pattern where remote username
  656. X     * lookups are desired, and plain host_pattern for all other cases. The
  657. X     * syntax of user name patterns is the same as for hosts or daemons, but
  658. X     * ALL is probably the only user_pattern that makes sense.
  659. X     * 
  660. X     * In case of UDP connections, the result of username lookup will always be
  661. X     * "unknown".
  662. X     * 
  663. X     * Return FAIL if we match a pattern of the form user@FAIL or FAIL@host:
  664. X     * FAIL, like NO, is transitive. According to some people, such patterns
  665. X     * should be taken out and shot. Good news: FAIL is on its way out.
  666. X     */
  667. X
  668. X    if (at = strchr(tok + 1, '@')) {        /* user@host */
  669. X    *at = 0;
  670. X    if (host_match = client_match(at + 1, item)) {
  671. X        if (client->user[0] == 0) {
  672. X        if (client->sock_type != FROM_CONNECTED) {
  673. X            client->user = FROM_UNKNOWN;
  674. X        } else if (client->sin == 0) {
  675. X            syslog(LOG_ERR, "no socket info for user name lookup");
  676. X            client->user = FROM_UNKNOWN;
  677. X        } else {
  678. X            client->user = rfc931_name(client->sin);
  679. X        }
  680. X        }
  681. X        user_match = string_match(tok, client->user);
  682. X        if (user_match == NO || user_match == FAIL) {
  683. X        match = user_match;
  684. X        } else {
  685. X        match = host_match;
  686. X        }
  687. X    }
  688. X    *at = '@';
  689. X    } else {                    /* host */
  690. X    match = client_match(tok, item);
  691. X    }
  692. X    return (match);
  693. X}
  694. X
  695. X#endif /* USER_AT_HOST */
  696. X
  697. X/* string_match - match string against token */
  698. X
  699. Xstatic int string_match(tok, string)
  700. Xchar   *tok;
  701. Xchar   *string;
  702. X{
  703. X    int     tok_len;
  704. X    int     str_len;
  705. X    char   *cut;
  706. X#ifdef    NETGROUP
  707. X    static char *mydomain = 0;
  708. X#endif
  709. X
  710. X    /*
  711. X     * Return YES if a token has the magic value "ALL". Return FAIL if the
  712. X     * token is "FAIL". If the token starts with a "." (domain name), return
  713. X     * YES if it matches the last fields of the string. If the token has the
  714. X     * magic value "LOCAL", return YES if the string does not contain a "."
  715. X     * character. If the token ends on a "." (network number), return YES if
  716. X     * it matches the first fields of the string. If the token begins with a
  717. X     * "@" (netgroup name), return YES if the string is a (host) member of
  718. X     * the netgroup. Return YES if the token fully matches the string. If the
  719. X     * token is a netnumber/netmask pair, return YES if the address is a
  720. X     * member of the specified subnet.
  721. X     */
  722. X
  723. X    if (tok[0] == '.') {            /* domain: match last fields */
  724. X    if ((str_len = strlen(string)) > (tok_len = strlen(tok))
  725. X        && strcasecmp(tok, string + str_len - tok_len) == 0)
  726. X        return (YES);
  727. X    } else if (tok[0] == '@') {            /* netgroup: look it up */
  728. X#ifdef    NETGROUP
  729. X    if (mydomain == 0)
  730. X        yp_get_default_domain(&mydomain);
  731. X    if (!isdigit(string[0])
  732. X        && innetgr(tok + 1, string, (char *) 0, mydomain))
  733. X        return (YES);
  734. X#else
  735. X    syslog(LOG_ERR, "wrapper: netgroup support is not configured");
  736. X    return (NO);
  737. X#endif
  738. X    } else if (strcasecmp(tok, "ALL") == 0) {    /* all: match any */
  739. X    return (YES);
  740. X    } else if (strcasecmp(tok, "FAIL") == 0) {    /* fail: match any */
  741. X    return (FAIL);
  742. X    } else if (strcasecmp(tok, "LOCAL") == 0) {    /* local: no dots */
  743. X    if (strchr(string, '.') == 0 && strcasecmp(string, "unknown") != 0)
  744. X        return (YES);
  745. X    } else if (!strcasecmp(tok, string)) {    /* match host name or address */
  746. X    return (YES);
  747. X    } else if (tok[(tok_len = strlen(tok)) - 1] == '.') {    /* network */
  748. X    if (strncmp(tok, string, tok_len) == 0)
  749. X        return (YES);
  750. X    } else if ((cut = strchr(tok, '/')) != 0) {    /* netnumber/netmask */
  751. X    if (isdigit(string[0]) && masked_match(tok, cut, string))
  752. X        return (YES);
  753. X    }
  754. X    return (NO);
  755. X}
  756. X
  757. X/* masked_match - match address against netnumber/netmask */
  758. X
  759. Xstatic int masked_match(tok, slash, string)
  760. Xchar   *tok;
  761. Xchar   *slash;
  762. Xchar   *string;
  763. X{
  764. X    unsigned long net;
  765. X    unsigned long mask;
  766. X    unsigned long addr;
  767. X
  768. X    if ((addr = inet_addr(string)) == INADDR_NONE)
  769. X    return (NO);
  770. X    *slash = 0;
  771. X    net = inet_addr(tok);
  772. X    *slash = '/';
  773. X    if (net == INADDR_NONE || (mask = inet_addr(slash + 1)) == INADDR_NONE) {
  774. X    syslog(LOG_ERR, "bad net/mask access control: %s", tok);
  775. X    return (NO);
  776. X    }
  777. X    return ((addr & mask) == net);
  778. X}
  779. X
  780. X/* xgets - fgets() with backslash-newline stripping */
  781. X
  782. Xstatic char *xgets(buf, len, fp)
  783. Xchar   *buf;
  784. Xint     len;
  785. XFILE   *fp;
  786. X{
  787. X    int     got;
  788. X    char   *start = buf;
  789. X
  790. X    for (;;) {
  791. X    if (fgets(buf, len, fp) == 0)
  792. X        return (buf > start ? start : 0);
  793. X    got = strlen(buf);
  794. X    if (got >= 2 && buf[got - 2] == '\\' && buf[got - 1] == '\n') {
  795. X        got -= 2;
  796. X        buf += got;
  797. X        len -= got;
  798. X        buf[0] = 0;
  799. X    } else {
  800. X        return (start);
  801. X    }
  802. X    }
  803. X}
  804. END_OF_hosts_access.c
  805. if test 11173 -ne `wc -c <hosts_access.c`; then
  806.     echo shar: \"hosts_access.c\" unpacked with wrong size!
  807. fi
  808. # end of overwriting check
  809. fi
  810. if test -f options.c -a "${1}" != "-c" ; then 
  811.   echo shar: Will not over-write existing file \"options.c\"
  812. else
  813. echo shar: Extracting \"options.c\" \(10084 characters\)
  814. sed "s/^X//" >options.c <<'END_OF_options.c'
  815. X /*
  816. X  * General skeleton for adding options to the access control language. The
  817. X  * Makefile describes how this alternative language is enabled. Shell
  818. X  * commands will still be available, be it with a slightly different syntax.
  819. X  * 
  820. X  * The code uses a slightly different format of access control rules. It
  821. X  * assumes that an access control rule looks like this:
  822. X  * 
  823. X  * daemon_list : client_list : option : option ...
  824. X  * 
  825. X  * An option is of the form "keyword" or "keyword = value". Option fields are
  826. X  * processed from left to right. Blanks around keywords, "="  and values are
  827. X  * optional. Blanks within values are left alone.
  828. X  * 
  829. X  * Diagnostics are reported through syslog(3).
  830. X  * 
  831. X  * Examples of options that are already implemented by the current skeleton:
  832. X  * 
  833. X  * user = nobody
  834. X  * 
  835. X  * Causes the process to switch its user id to that of "nobody". This normally
  836. X  * requires root privilege.
  837. X  * 
  838. X  * group = tty
  839. X  * 
  840. X  * Causes the process to change its group id to that of the "tty" group. In
  841. X  * order to switch both user and group ids you should normally switch the
  842. X  * group id before switching the user id.
  843. X  * 
  844. X  * setenv = name value
  845. X  * 
  846. X  * places a name,value pair into the environment. The value is subjected to
  847. X  * %<character> expansions.
  848. X  * 
  849. X  * spawn = (/usr/ucb/finger -l @%h | /usr/ucb/mail root) &
  850. X  * 
  851. X  * Executes (in a background child process) the shell command "finger -l @%h |
  852. X  * mail root" after doing the %<character> expansions described in the
  853. X  * hosts_access(5) manual page. The command is executed with stdin, stdout
  854. X  * and stderr connected to the null device. Because options are processed in
  855. X  * order, multiple spawn comands can be specified within the same access
  856. X  * control rule, though "spawn = command1; command2" would be more
  857. X  * efficient.
  858. X  * 
  859. X  * in.ftpd : ... : twist = /bin/echo 421 Some customized bounce message
  860. X  * 
  861. X  * Sends some custmized bounce message to the remote client instead of running
  862. X  * the real ftp daemon. The command is subjected to %<character> expansion
  863. X  * before execution by /bin/sh. Stdin, stdout and stderr are connected to the
  864. X  * remote client process. The twist'ed command overlays the current process;
  865. X  * it makes no sense to specify other options on the same line after a
  866. X  * "twist". The "twist" option was inspired by Dan Bernstein's shuctl daemon
  867. X  * wrapper control language.
  868. X  * 
  869. X  * umask = value
  870. X  * 
  871. X  * Sets the process file creation mask. Value must be an octal number.
  872. X  * 
  873. X  * If you compile with -DRFC_OPTION, code is enabled for the following option
  874. X  * that does selective rfc931 lookups.
  875. X  * 
  876. X  * rfc931
  877. X  * 
  878. X  * Causes the daemon front ends to look up the remote user name with the RFC
  879. X  * 931 protocol.
  880. X  * 
  881. X  * Warnings:
  882. X  * 
  883. X  * This module uses the non-reentrant strtok() library routine. The options
  884. X  * argument to process_options() is destroyed.
  885. X  * 
  886. X  * There cannot be a ":" character in keywords or values. Backslash sequences
  887. X  * are not yet recognized.
  888. X  * 
  889. X  * In case of UDP connections, do not "twist" commands that use the standard
  890. X  * I/O or read(2)/write(2) routines to communicate with the client process;
  891. X  * UDP requires other communications primitives.
  892. X  * 
  893. X  * In case of errors, use clean_exit() instead of directly calling exit(), or
  894. X  * your inetd may loop on an UDP request.
  895. X  */
  896. X
  897. X/* System libraries. */
  898. X
  899. X#include <sys/types.h>
  900. X#include <sys/param.h>
  901. X#include <sys/socket.h>
  902. X#include <sys/stat.h>
  903. X#include <netinet/in.h>
  904. X#include <netdb.h>
  905. X#include <stdio.h>
  906. X#include <syslog.h>
  907. X#include <pwd.h>
  908. X#include <grp.h>
  909. X#include <ctype.h>
  910. X
  911. Xextern char *strtok();
  912. Xextern char *strchr();
  913. Xextern void closelog();
  914. X
  915. X/* Local stuff. */
  916. X
  917. X#include "log_tcp.h"
  918. X
  919. X/* List of functions that implement the options. Add yours here. */
  920. X
  921. Xstatic void user_option();        /* execute "user=name" option */
  922. Xstatic void group_option();        /* execute "group=name" option */
  923. Xstatic void umask_option();        /* execute "umask=mask" option */
  924. Xstatic void twist_option();        /* execute "twist=command" option */
  925. X#ifdef RFC931_OPTION
  926. Xstatic void rfc931_option();        /* execute "rfc931" option */
  927. X#endif
  928. Xstatic void setenv_option();        /* execute "setenv=name value" */
  929. X
  930. Xstatic char *chop_string();        /* strip leading and trailing blanks */
  931. X
  932. X/* Structure of the options table. */
  933. X
  934. Xstruct option {
  935. X    char   *name;            /* keyword name, case does not matter */
  936. X    int     need_value;            /* value required or not */
  937. X    void    (*func) ();            /* function that does the real work */
  938. X};
  939. X
  940. X/* List of known keywords. Add yours here. */
  941. X
  942. Xstatic struct option option_table[] = {
  943. X    "user", 1, user_option,        /* switch user id */
  944. X    "group", 1, group_option,        /* switch group id */
  945. X    "umask", 1, umask_option,        /* change umask */
  946. X    "spawn", 1, shell_cmd,        /* spawn shell command */
  947. X    "twist", 1, twist_option,        /* replace current process */
  948. X#ifdef RFC931_OPTION
  949. X    "rfc931", 0, rfc931_option,        /* do RFC 931 lookup */
  950. X#endif
  951. X    "setenv", 1, setenv_option,        /* update environment */
  952. X    0,
  953. X};
  954. X
  955. Xstatic char whitespace[] = " \t\r\n";
  956. X
  957. X/* process_options - process optional access control information */
  958. X
  959. Xprocess_options(options, daemon, client)
  960. Xchar   *options;
  961. Xchar   *daemon;
  962. Xstruct from_host *client;
  963. X{
  964. X    char   *key;
  965. X    char   *value;
  966. X    struct option *op;
  967. X
  968. X    /*
  969. X     * Light-weight parser. Remember, we may be running as root so we need
  970. X     * code that is easy to comprehend.
  971. X     */
  972. X
  973. X    for (key = strtok(options, ":"); key; key = strtok((char *) 0, ":")) {
  974. X    if (value = strchr(key, '=')) {        /* keyword=value */
  975. X        *value++ = 0;
  976. X        value = chop_string(value);        /* strip blanks around value */
  977. X        if (*value == 0)
  978. X        value = 0;            /* no value left */
  979. X    }
  980. X    key = chop_string(key);            /* strip blanks around key */
  981. X    for (op = option_table; op->name; op++)    /* find keyword */
  982. X        if (strcasecmp(op->name, key) == 0)
  983. X        break;
  984. X    if (op->name == 0) {
  985. X        syslog(LOG_ERR, "bad option or syntax: \"%s\"", key);
  986. X    } else if (value == 0 && op->need_value) {
  987. X        syslog(LOG_ERR, "option \"%s\" requires value", key);
  988. X    } else if (value && op->need_value == 0) {
  989. X        syslog(LOG_ERR, "option \"%s\" requires no value", key);
  990. X    } else {
  991. X        (*(op->func)) (value, daemon, client);
  992. X    }
  993. X    }
  994. X}
  995. X
  996. X/* user_option - switch user id */
  997. X
  998. X/* ARGSUSED */
  999. X
  1000. Xstatic void user_option(value, daemon, client)
  1001. Xchar   *value;
  1002. Xchar   *daemon;
  1003. Xstruct from_host *client;
  1004. X{
  1005. X    struct passwd *pwd;
  1006. X    struct passwd *getpwnam();
  1007. X
  1008. X    if ((pwd = getpwnam(value)) == 0) {
  1009. X    syslog(LOG_ERR, "unknown user: \"%s\"", value);
  1010. X    clean_exit(client);
  1011. X    } else if (setuid(pwd->pw_uid)) {
  1012. X    syslog(LOG_ERR, "setuid(%s): %m", value);
  1013. X    clean_exit(client);
  1014. X    }
  1015. X}
  1016. X
  1017. X/* group_option - switch group id */
  1018. X
  1019. X/* ARGSUSED */
  1020. X
  1021. Xstatic void group_option(value, daemon, client)
  1022. Xchar   *value;
  1023. Xchar   *daemon;
  1024. Xstruct from_host *client;
  1025. X{
  1026. X    struct group *grp;
  1027. X    struct group *getgrnam();
  1028. X
  1029. X    if ((grp = getgrnam(value)) == 0) {
  1030. X    syslog(LOG_ERR, "unknown group: \"%s\"", value);
  1031. X    clean_exit(client);
  1032. X    } else if (setgid(grp->gr_gid)) {
  1033. X    syslog(LOG_ERR, "setgid(%s): %m", value);
  1034. X    clean_exit(client);
  1035. X    }
  1036. X}
  1037. X
  1038. X/* umask_option - set file creation mask */
  1039. X
  1040. X/* ARGSUSED */
  1041. X
  1042. Xstatic void umask_option(value, daemon, client)
  1043. Xchar   *value;
  1044. Xchar   *daemon;
  1045. Xstruct from_host *client;
  1046. X{
  1047. X    unsigned mask;
  1048. X    char    junk;
  1049. X
  1050. X    if (sscanf(value, "%o%c", &mask, &junk) != 1 || (mask & 0777) != mask) {
  1051. X    syslog(LOG_ERR, "bad umask: \"%s\"", value);
  1052. X    clean_exit(client);
  1053. X    }
  1054. X    (void) umask(mask);
  1055. X}
  1056. X
  1057. X/* twist_option - replace process by shell command */
  1058. X
  1059. Xstatic void twist_option(value, daemon, client)
  1060. Xchar   *value;
  1061. Xchar   *daemon;
  1062. Xstruct from_host *client;
  1063. X{
  1064. X    char    buf[BUFSIZ];
  1065. X    int     pid = getpid();
  1066. X    char   *error;
  1067. X
  1068. X    percent_x(buf, sizeof(buf), value, daemon, client, pid);
  1069. X
  1070. X    /* Since we will not be logging in the usual way, do it here and now. */
  1071. X
  1072. X    syslog(SEVERITY, "twist from %s to %s", hosts_info(client), buf);
  1073. X    closelog();
  1074. X
  1075. X    /*
  1076. X     * Before switching to the shell, set up stdout and stderr in case the
  1077. X     * Ultrix inetd didn't.
  1078. X     */
  1079. X
  1080. X    (void) close(1);
  1081. X    (void) close(2);
  1082. X    if (dup(0) != 1 || dup(0) != 2) {
  1083. X    error = "dup: %m";
  1084. X    } else {
  1085. X    (void) execl("/bin/sh", "sh", "-c", buf, (char *) 0);
  1086. X    error = "/bin/sh: %m";
  1087. X    }
  1088. X
  1089. X    /* Can get here only in case of errors. */
  1090. X
  1091. X#ifdef LOG_MAIL
  1092. X    (void) openlog(daemon, LOG_PID, FACILITY);
  1093. X#else
  1094. X    (void) openlog(daemon, LOG_PID);
  1095. X#endif
  1096. X    syslog(LOG_ERR, error);
  1097. X    clean_exit(client);
  1098. X}
  1099. X
  1100. X#ifdef RFC931_OPTION
  1101. X
  1102. X/* rfc931_option - look up remote user name */
  1103. X
  1104. X/* ARGSUSED */
  1105. X
  1106. Xstatic void rfc931_option(value, daemon, client)
  1107. Xchar   *value;
  1108. Xchar   *daemon;
  1109. Xstruct from_host *client;
  1110. X{
  1111. X    if (client->sock_type == FROM_CONNECTED) {
  1112. X    if (client->sin == 0) {
  1113. X        syslog(LOG_ERR, "no socket info for username lookup");
  1114. X    } else {
  1115. X        client->user = rfc931_name(client->sin);
  1116. X    }
  1117. X    }
  1118. X}
  1119. X
  1120. X#endif
  1121. X
  1122. X/* setenv_option - set environment variable */
  1123. X
  1124. X/* ARGSUSED */
  1125. X
  1126. Xstatic void setenv_option(value, daemon, client)
  1127. Xchar   *value;
  1128. Xchar   *daemon;
  1129. Xstruct from_host *client;
  1130. X{
  1131. X    char   *var_name;
  1132. X    char   *var_value;
  1133. X    char    buf[BUFSIZ];
  1134. X    int     pid;
  1135. X
  1136. X    /*
  1137. X     * What we get is one string with the name and the value separated by
  1138. X     * whitespace. Find the end of the name. If that is also the end of the
  1139. X     * string, the value is empty.
  1140. X     */
  1141. X
  1142. X    var_value = value + strcspn(value, whitespace);
  1143. X
  1144. X    if (*var_value == 0) {            /* just a name, that's all */
  1145. X    var_name = value;
  1146. X    } else {                    /* expand %stuff in value */
  1147. X    *var_value++ = 0;
  1148. X    var_name = chop_string(value);
  1149. X    pid = getpid();
  1150. X    percent_x(buf, sizeof(buf), var_value, daemon, client, pid);
  1151. X    var_value = chop_string(buf);
  1152. X    }
  1153. X    if (setenv(var_name, var_value, 1)) {
  1154. X    syslog(LOG_ERR, "memory allocation failure");
  1155. X    clean_exit(client);
  1156. X    }
  1157. X}
  1158. X
  1159. X/* chop_string - strip leading and trailing blanks from string */
  1160. X
  1161. Xstatic char *chop_string(start)
  1162. Xregister char *start;
  1163. X{
  1164. X    register char *end;
  1165. X
  1166. X    while (*start && isspace(*start))
  1167. X    start++;
  1168. X
  1169. X    for (end = start + strlen(start); end > start && isspace(end[-1]); end--)
  1170. X     /* void */ ;
  1171. X    *end = 0;
  1172. X
  1173. X    return (start);
  1174. X}
  1175. END_OF_options.c
  1176. if test 10084 -ne `wc -c <options.c`; then
  1177.     echo shar: \"options.c\" unpacked with wrong size!
  1178. fi
  1179. # end of overwriting check
  1180. fi
  1181. echo shar: End of archive 3 \(of 3\).
  1182. cp /dev/null ark3isdone
  1183. MISSING=""
  1184. for I in 1 2 3 ; do
  1185.     if test ! -f ark${I}isdone ; then
  1186.     MISSING="${MISSING} ${I}"
  1187.     fi
  1188. done
  1189. if test "${MISSING}" = "" ; then
  1190.     echo You have unpacked all 3 archives.
  1191.     rm -f ark[1-9]isdone
  1192. else
  1193.     echo You still need to unpack the following archives:
  1194.     echo "        " ${MISSING}
  1195. fi
  1196. ##  End of shell archive.
  1197. exit 0
  1198.  
  1199. exit 0 # Just in case...
  1200.